package com.atguigu.aop.proxy;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

@Component
@Aspect
@Order(value = 2)
public class AtguiguLogAspect {

    // value 属性：指定切入点表达式，告诉框架把前置通知的操作用在哪个（或哪些）目标方法上
    @Before(value = "com.atguigu.aop.proxy.AtguiguPointCut.myPointCut()")
    public void myBeforeOperation(JoinPoint joinPoint) {

        // 通过 JoinPoint 参数可以获取目标方法的相关信息
        // 1、通过 JoinPoint 对象获取目标方法的签名（签名：包含方法声明相关的所有信息）
        Signature signature = joinPoint.getSignature();

        // 2、通过签名对象获取目标方法的名称
        String methodName = signature.getName();

        // 3、通过 JoinPoint 对象获取外界调用目标方法时，传入的实参列表组成的数组
        Object[] args = joinPoint.getArgs();

        // 4、为了便于打印实参列表中的数，把数组转换为 List 集合
        List<Object> argList = ((args == null || args.length == 0) ? null : Arrays.asList(args));

        // 5、根据上面获取的信息打印日志
        System.out.println("[前置通知][方法名："+methodName+"][参数列表："+argList+"]");
    }

    // returning 属性：指定接收目标方法返回值参数的名称
    @AfterReturning(value = "com.atguigu.aop.proxy.AtguiguPointCut.myPointCut()", returning = "result")
    public void mySuccessOperation(JoinPoint joinPoint,

                                   // 框架会把目标方法的返回值从 result 这个参数的位置传入
                                   Object result) {
        Signature signature = joinPoint.getSignature();
        String methodName = signature.getName();

        System.out.println("[返回通知][方法名："+methodName+"][目标方法返回值："+result+"]");
    }

    // throwing 属性：指定接收目标方法抛出异常的参数名称
    @AfterThrowing(value = "com.atguigu.aop.proxy.AtguiguPointCut.myPointCut()", throwing = "exception")
    public void myFailedOperation(JoinPoint joinPoint, Exception exception) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("[异常通知][方法名："+methodName+"][异常信息："+exception+"]");
    }

    @After(value = "com.atguigu.aop.proxy.AtguiguPointCut.myPointCut()")
    public void myFinishedOperation(JoinPoint joinPoint) {
        System.out.println("[后置通知][方法名："+joinPoint.getSignature().getName()+"]");
    }
}
